﻿#include "connection.h"

#include <cassert>
#include "log.h"
#include "channel.h"
#include "eventloop.h"

Connection::Connection(EventLoop *eloop, uint64_t conn_id, int sockfd)
    : m_eloop(eloop)
    , m_conn_id(conn_id)
    , m_sockfd(sockfd)
    , m_socket(sockfd)
    , m_channel(eloop, sockfd)
    , m_cstatus(ConStatus::CONNECTING)
    , m_enableInactiveRelease(false)
{
    m_channel.setReadCallback(std::bind(&Connection::handleRead, this));
    m_channel.setWriteCallback(std::bind(&Connection::handleWrite, this));
    m_channel.setCloseCallback(std::bind(&Connection::handleClose, this));
    m_channel.setErrorCallback(std::bind(&Connection::handleError, this));
}

Connection::~Connection()
{
    LOG(Info, "Connection::~Connection()");
}

// 子函数
void Connection::handleRead()
{
    // 1. 读取socket的数据, 放入用户缓冲区
    char buf[BUFF_64KB] = {0};
    ssize_t ret = m_socket.nonBlockRecv(buf, BUFF_64KB);
    if (ret < 0)
    {
        //NOTE: 出错了，不能直接关闭
        return _shutDown();
    }
    m_inBuffer.write(buf, ret);
    // 2. 调用message_cb
    if (m_inBuffer.getReadSize() > 0)
    {
        return  m_messageCb(shared_from_this(), &m_inBuffer);
    } 
}

void Connection::handleWrite()
{
    // 1. 发送数据到socket
    ssize_t ret = m_socket.nonBlockSend(m_outBuffer.getReadAddr(), m_outBuffer.getReadSize());
    if (ret < 0)
    {
        // 发送错误就该关闭连接了，
        if (m_inBuffer.getReadSize() > 0)
        {
            m_messageCb(shared_from_this(), &m_inBuffer);
        }
        return release(); // 这时候就是实际的关闭释放操作了。
    }
    // 2. 移动读取位置
    // NOTE: 别忘了移动读取位置 
    m_outBuffer.moveReadStep(ret);
    // 3. 如果缓冲区没有数据了，则关闭写事件
    if (m_outBuffer.getReadSize() == 0)
    {
        m_channel.disableWrite();
        // NOTE: 如果连接状态为待关闭，则可以进行释放
        if(m_cstatus == ConStatus::DISCONNECTING)
        {
            release();
        }
    }
}

void Connection::handleClose()
{
    // 1. 先检查in_buffer是否还有数据
    // NOTE: TCP的4次挥手，如果in_buffer还有数据，则先处理，再释放
    if (m_inBuffer.getReadSize() > 0)
    {
        m_messageCb(shared_from_this(), &m_inBuffer);
    }
    // 2. 关闭连接
    release();
}

void Connection::handleError()
{
    handleClose();
}

void Connection::handleAny()
{
    // 1. 如果启动了超时销毁，先刷新一下活跃度
    if(m_enableInactiveRelease == true)
    {
        m_eloop->refreshTimerTask(m_conn_id);
    }
    // 2. 调用任意事件回调
    if(m_anyCb)
    {
        m_anyCb(shared_from_this());
    }
}

// 发送数据
void Connection::_send(Buffer &buf)
{
    // 1. 如果连接状态为断开，则不发送
    if(m_cstatus == ConStatus::DISCONNECTED)
    {
        return;
    }
    // 2. 将数据发到发送缓冲区
    m_outBuffer.writeBuffer(buf);
    // 3. 启动可写监控
    if(m_channel.isWriteAble() == false)
    {
        m_channel.enableWrite();
    }
}

// NOTE: 在关闭连接时，先处理未处理的数据，再释放
void Connection::_shutDown()
{
    // 1. 设置连接为待关闭状态
    m_cstatus = ConStatus::DISCONNECTING;
    // 2. 先处理未处理的数据
    if(m_inBuffer.getReadSize() > 0)
    {
        if(m_messageCb)
        {
            m_messageCb(shared_from_this(), &m_inBuffer);
        }
    }
    if(m_outBuffer.getReadSize() > 0)
    {
        if(m_channel.isWriteAble() == false)
        {
            m_channel.enableWrite();
        }
    }
    // 2. 如果所有数据都处理完了，则释放
    if(m_outBuffer.getReadSize() == 0)
    {
        release();
    }
}
// 启动非活跃连接的超时销毁功能
void Connection::_enableInactiveRelease(int sec)
{
    // 1. 设置标志位
    m_enableInactiveRelease = true;
    // 2. 设置定时任务
    // NOTE: 如果已经存在定时任务，则刷新定时任务
    if(m_eloop->hasTimerTask(m_conn_id) == true)
    {
        return m_eloop->refreshTimerTask(m_conn_id);
    }
    return m_eloop->addTimerTask(m_conn_id, sec, std::bind(&Connection::release, this));
}
// 取消非活跃连接的超时销毁功能
void Connection::_disableInactiveRelease()
{
    // 1. 设置标志位
    m_enableInactiveRelease = false;
    // 2. 取消定时任务
    if(m_eloop->hasTimerTask(m_conn_id) == true)
    {
        return m_eloop->cancelTimerTask(m_conn_id);
    }
}
// NOTE: 释放连接, 真正的关闭连接
void Connection::_release()
{
    // 1. 设置连接状态
    m_cstatus = ConStatus::DISCONNECTED;
    // 2. 删除事件监控
    m_channel.remove();
    // 3. 关闭套接字
    m_socket.close();
    // 4. 取消超时销毁
    _disableInactiveRelease();
    // 5. 调用关闭回调
    if(m_closeCb)
    {
        m_closeCb(shared_from_this());
    }
    // 6. 调用组件内部关闭回调
    // NOTE: 先调用用户设置的回调，再调用组件内部设置的回调
    if(m_serverCloseCb)
    {
        m_serverCloseCb(shared_from_this());
    }
}
// 建立连接
void Connection::_establishConnection()
{
    // 1. 修改连接状态
    assert(m_cstatus == ConStatus::CONNECTING);
    m_cstatus = ConStatus::CONNECTED;
    // 2. 启动可读监控
    // NOTE: 其实可以不用判断，因为连接刚建立时，一定要启动可读事件监控
    m_channel.enableRead();
    // 3. 调用连接回调
    if(m_connectCb)
    {
        m_connectCb(shared_from_this());
    }
}

// 切换协议
void Connection::_upgrade(const Any &context,
                        const ConnectCallback &con, const MessageCallback &mes,
                        const CloseCallback &clo, const AnyCallback &an)
{
    m_context = context;
    m_connectCb = con;
    m_messageCb = mes;
    m_closeCb = clo;
    m_anyCb = an;
}

// 公有函数
// 设置连接状态
void Connection::setConStatus(ConStatus status)
{
    m_cstatus = status;
}
// 获取连接状态
ConStatus Connection::getConStatus() const
{
    return m_cstatus;
}
// 判断连接是否连接
bool Connection::isConnected() const
{
    return m_cstatus == ConStatus::CONNECTED;
}
// 获取连接id
uint64_t Connection::getConnId() const
{
    return m_conn_id;
}
// 获取套接字文件描述符
int Connection::getSockfd() const
{
    return m_sockfd;
}
// 获取套接字
Socket &Connection::getSocket()
{
    return m_socket;
}
// 获取事件循环
EventLoop *Connection::getEventLoop()
{
    return m_eloop;
}


// 上下文管理 -------------------------------------
// 设置上下文
void Connection::setContext(const Any &context)
{
    m_context = context;
}
// 获取上下文
Any* Connection::getContext()
{
    return &m_context;
}
// 切换协议
void Connection::upgrade(const Any &context,
                        const ConnectCallback &con, const MessageCallback &mes,
                        const CloseCallback &clo, const AnyCallback &an)
{
    //NOTE:: 切换协议必须立即执行，否则可能导致新事件用旧协议
    m_eloop->assertInLoop();
    m_eloop->runInLoop(std::bind(&Connection::_upgrade, this, context, con, mes, clo, an));
}

// 通信数据交互 ----------------------------------------------
// 发送数据
void Connection::send(const char* data, size_t size)
{
    // NOTE: 这里为什么要使用buffer？
    // runInLoop只是将任务压入队列，不一定会立即执行，而data可能被释放或修改，因此要先保存一份
    Buffer buf;
    buf.write(data, size);
    m_eloop->runInLoop(std::bind(&Connection::_send, this, buf));
}



// 修改连接状态相关的函数 -------------------------------------
// 关闭连接
void Connection::shutDown()
{
    m_eloop->runInLoop(std::bind(&Connection::_shutDown, this));
}
// 启动非活跃连接的超时销毁功能
void Connection::enableInactiveRelease(int sec)
{
    m_eloop->runInLoop(std::bind(&Connection::_enableInactiveRelease, this, sec));
}
// 取消非活跃连接的超时销毁功能
void Connection::disableInactiveRelease()
{
    m_eloop->runInLoop(std::bind(&Connection::_disableInactiveRelease, this));
}
// 释放连接
void Connection::release()
{
    m_eloop->runInLoop(std::bind(&Connection::_release, this));
}
// 建立连接
void Connection::establishConnection()
{
    m_eloop->runInLoop(std::bind(&Connection::_establishConnection, this));
}

// 设置回调函数 -------------------------------------
// 设置连接回调函数
void Connection::setConnectCallback(const ConnectCallback &cb)
{
    m_connectCb = cb;
}
// 设置消息回调函数
void Connection::setMessageCallback(const MessageCallback &cb)
{
    m_messageCb = cb;
}
// 设置连接关闭回调
void Connection::setCloseCallback(const CloseCallback &cb)
{
    m_closeCb = cb;
}
// 设置任意事件回调
void Connection::setAnyCallback(const AnyCallback &cb)
{
    m_anyCb = cb;
}
// 设置服务器关闭回调
void Connection::setServerCloseCallback(const CloseCallback &cb)
{
    m_serverCloseCb = cb;
}





